﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Xml.Linq;
using VisionFrame.Base;
using VisionFrame.Base.Models;
using VisionFrame.Models;
using VisionFrame.Nodes;

namespace VisionFrame.ViewModels
{
    public class FlowTabViewModel : ObservableObject, IFlowContext
    {
        private bool _isCurrent;

        public bool IsCurrent
        {
            get { return _isCurrent; }
            set
            {
                SetProperty<bool>(ref _isCurrent, value);

                if (!value) TitleEditVisible = Visibility.Hidden;
            }
        }

        #region Title与编辑
        private string _title;

        public string Title
        {
            get { return _title; }
            set { SetProperty<string>(ref _title, value); }
        }


        private Visibility _titleEditVisible = Visibility.Hidden;

        public Visibility TitleEditVisible
        {
            get { return _titleEditVisible; }
            set { SetProperty<Visibility>(ref _titleEditVisible, value); }
        }


        public ICommand SelectCommand { get; set; }
        public ICommand EditTitleCommand { get; set; }
        public ICommand AcceptTitleCommand { get; set; }
        #endregion

        #region 节点创建
        public ObservableCollection<NodeModelBase> NodeList { get; set; } =
            new ObservableCollection<NodeModelBase>();

        public ICommand DragDropCommand { get; set; }

        public ICommand DeleteElementCommand { get; set; }
        #endregion

        #region 连线集合
        public ObservableCollection<LinkModel> LinkList { get; set; } =
            new ObservableCollection<LinkModel>();
        #endregion

        #region 节点移动相关动作
        public ICommand NodeMouseDownCommand { get; set; }
        public ICommand NodeMouseMoveCommand { get; set; }
        public ICommand NodeMouseUpCommand { get; set; }
        #endregion

        #region 锚点操作
        public ICommand AnchorDownCommand { get; set; }
        public ICommand AnchorUpCommand { get; set; }
        #endregion

        #region 流程控制
        public ICommand RunCommand { get; set; }
        public ICommand CircleCommand { get; set; }
        public ICommand StopCommand { get; set; }
        public ICommand StepCommand { get; set; }
        #endregion

        #region 流程参数管理
        public ObservableCollection<FlowArgModel> ArgumentList { get; set; } =
            new ObservableCollection<FlowArgModel>();

        public ICommand AddArgumentCommand { get; set; }
        public ICommand DelArgumentCommand { get; set; }

        public List<string> ArgTypeList { get; set; } = new List<string>
        {
            "Int32","IntPtr","Double","String","Boolean"
        };


        // 参数处理相关命令
        public ICommand SelectFolderCommand { get; set; }
        #endregion

        private ImageSource _previewImage;
        /// <summary>
        /// 预览图像
        /// </summary>
        public ImageSource PreviewImage
        {
            get { return _previewImage; }
            set { SetProperty<ImageSource>(ref _previewImage, value); }
        }


        public ObservableCollection<LogModel> LogList { get; set; } =
            new ObservableCollection<LogModel>();


        //画布缩放
        #region 画布缩放
        private double _mainZoom = 1.0;

        public double MainZoom
        {
            get { return _mainZoom; }
            set { SetProperty<double>(ref _mainZoom, value); }
        }

        private double _dragX = 0;

        public double DragX
        {
            get { return _dragX; }
            set { SetProperty<double>(ref _dragX, value); }
        }

        private double _dragY = 0;

        public double DragY
        {
            get { return _dragY; }
            set { SetProperty<double>(ref _dragY, value); }
        }

        public ICommand MouseWheelCommand { get; set; }

        public ICommand CanvasMouseDownCommand { get; set; }
        public ICommand CanvasMouseUpCommand { get; set; }
        public ICommand CanvasMouseMoveCommand { get; set; }

        public ICommand ZoomIncreaseCommand { get; set; }
        public ICommand ZoomReduceCommand { get; set; }
        public ICommand ZoomResetCommand { get; set; }
        #endregion

        #region 鹰眼视图
        private double _hwakeyeZoom = 1.0;

        public double HwakeyeZoom
        {
            get { return _hwakeyeZoom; }
            set { SetProperty<double>(ref _hwakeyeZoom, value); }
        }

        private double _hwakeyeDragX;

        public double HwakeyeDragX
        {
            get { return _hwakeyeDragX; }
            set { SetProperty<double>(ref _hwakeyeDragX, value); }
        }
        private double _hwakeyeDragY;

        public double HwakeyeDragY
        {
            get { return _hwakeyeDragY; }
            set { SetProperty<double>(ref _hwakeyeDragY, value); }
        }

        #endregion


        public List<string> Operator { get; set; } = new List<string>
        {
            "=","<",">","<=",">=","!="
        };

        public FlowTabViewModel()
        {
            SelectCommand = new RelayCommand(() =>
            {
                this.IsCurrent = true;
            });
            DragDropCommand = new RelayCommand<object>(OnDragDrop);

            DeleteElementCommand = new RelayCommand<object>(DoElementDelete);

            #region Tab Title编辑动作
            EditTitleCommand = new RelayCommand(() =>
            {
                TitleEditVisible = Visibility.Visible;
            });
            AcceptTitleCommand = new RelayCommand(() =>
            {
                TitleEditVisible = Visibility.Hidden;
            });
            #endregion

            #region 节点移动动作
            NodeMouseDownCommand = new RelayCommand<object>(OnNodeMouseDown);
            NodeMouseMoveCommand = new RelayCommand<object>(OnNodeMove);
            NodeMouseUpCommand = new RelayCommand(OnNodeMouseUp);
            #endregion

            //默认起始节点添加
            string node_name = "VisionFrame.Nodes.StartNode";
            //INodeBase node = Activator.CreateInstance(Assembly.GetExecutingAssembly().GetType(node_name)) as INodeBase;
            //node.AnchorDownCommand = new RelayCommand<object>(OnAnchorDown);
            NodeList.Add(new StartNodeModel
            {
                IsStart = true,
                TargetNodeObject = node_name,
                X = 600,
                Y = 450,
                W = 100,
                H = 34,
                FlowLevel = new List<int> { 0 }
            });


            // 流程控制
            RunCommand = new RelayCommand(DoRunFlowchart);
            CircleCommand = new RelayCommand(DoCircleExecute);
            StopCommand = new RelayCommand(DoStopExecute);
            StepCommand = new RelayCommand(DoStepExecute);

            // 添加参数
            AddArgumentCommand = new RelayCommand(DoAddArgument);
            DelArgumentCommand = new RelayCommand<object>(DoDelArgument);

            // 参数列表命令
            SelectFolderCommand = new RelayCommand<object>(DoSelectFolder);


            // 锚点控制
            AnchorDownCommand = new RelayCommand<object>(DoAnchorDown);
            AnchorUpCommand = new RelayCommand<object>(DoAnchorUp);


            // 缩放操作
            //MouseWheelCommand = new RelayCommand<object>(DoMainZoom);

            CanvasMouseDownCommand = new RelayCommand<object>(DoCanvasMouseDown);
            CanvasMouseUpCommand = new RelayCommand<object>(DoCanvasMouseUp);
            //CanvasMouseMoveCommand = new RelayCommand<object>(DoCanvasMouseMove);

            ZoomIncreaseCommand = new RelayCommand<object>(DoZoomIncrease);
            ZoomReduceCommand = new RelayCommand<object>(DoZoomReduce);
            ZoomResetCommand = new RelayCommand<object>(DoZoomReset);
        }

        // 这个命令是ItemsControl执行
        private void OnDragDrop(object obj)
        {
            var e = obj as DragEventArgs;

            var component_model = e.Data.GetData(typeof(ComponentModel)) as ComponentModel;

            // 动态创建出来的节点对象
            //object instance = GetInstance(component_model.TargetNode);
            // 关联锚点动作事件命令
            //(instance as INodeBase).AnchorDownCommand =
            //    new RelayCommand<object>(OnAnchorDown);
            //(instance as INodeBase).AnchorUpCommand =
            //    new RelayCommand<object>(OnAnchorUp);

            // 获取鼠标松开时的坐标
            Point point = e.GetPosition((IInputElement)e.Source);

            // 创建每个显示节点所对应的数据Model
            string model_str = component_model.TargetModel;
            NodeModelBase node_model =
                (NodeModelBase)this.GetInstance(component_model.TargetModel);

            //node_model.TargetNodeObject = instance;
            node_model.TargetNodeObject = component_model.TargetNode;
            node_model.IsDecision = node_model is DecisionNodeModelBase;

            node_model.X = point.X - component_model.W / 2;
            node_model.Y = point.Y - component_model.H / 2;
            node_model.W = component_model.W;
            node_model.H = component_model.H;


            NodeList.Add(node_model);
        }

        private object GetInstance(string target)
        {
            string[] _info = target.Split(";");

            Assembly assembly =
                Assembly.LoadFile(Environment.CurrentDirectory + "/Activities/" + _info[0] + ".dll");
            if (assembly == null) return null;

            Type type = assembly.GetType(_info[1]);
            if (type == null) return null;

            return Activator.CreateInstance(type);
        }

        private void DoElementDelete(object obj)
        {
            if (obj is NodeModelBase model)
            {
                var links = this.LinkList.Where(l => l.StartId == model.NodeId || l.EndId == model.NodeId)
                    .ToList();
                int len = links.Count;
                for (int i = len - 1; i >= 0; i--)
                {
                    this.LinkList.Remove(links[i]);

                    RestAnchorShow(links[i]);
                }
                this.NodeList.Remove(model);

                // 后续节点的Level信息的同步更新

                // .....
            }
            else if (obj is LinkModel linkModel)
            {
                this.LinkList.Remove(linkModel);

                RestAnchorShow(linkModel);
            }

            isCanvasDrag = false;
            isLinking = false;
            is_hwakeye_drag = false;
        }
        private void RestAnchorShow(LinkModel model)
        {
            var start_node = NodeList.FirstOrDefault(n => n.NodeId == model.StartId);
            start_node?.SetAnchorShow(model.StartAnchor, true);

            var end_node = NodeList.FirstOrDefault(n => n.NodeId == model.EndId);
            end_node?.SetAnchorShow(model.EndAnchor, true);
        }


        #region 处理节点移动
        bool _is_moving = false;
        public NodeModelBase CurrentNodeModel { get; set; } = new NodeModelBase();

        Point _node_point = new Point();
        // 这个命令是由创建出来的节点触发的
        private void OnNodeMouseDown(object obj)
        {
            var e = obj as MouseEventArgs;

            if (CurrentNodeModel != null)
            {
                CurrentNodeModel.IsShowProperties = false;
                CurrentNodeModel.IsSelected = false;
            }

            CurrentNodeModel = (e.Source as FrameworkElement).DataContext as NodeModelBase;

            if (CurrentNodeModel != null)
            {
                CurrentNodeModel.IsSelected = true;

                // 修改Model中X和Y   至使页面节点进行位置更新
                // 什么时候？鼠标移动的时候
                //model.X
                _node_point = e.GetPosition((IInputElement)e.Source);

                _is_moving = true;
            }
            else
                CurrentNodeModel = new NodeModelBase();
            this.OnPropertyChanged(nameof(CurrentNodeModel));

            e.Handled = true;
        }

        // 命令是由ItemsControl触发的
        private void OnNodeMove(object obj)
        {
            var e = obj as MouseEventArgs;
            Point current_point = e.GetPosition((IInputElement)e.Source);
            // 节点移动的时候
            if (_is_moving)
            {
                // 根据光标位置   将节点进行移动
                CurrentNodeModel.X = current_point.X - _node_point.X;
                CurrentNodeModel.Y = current_point.Y - _node_point.Y;

                #region 更新连线坐标
                var start_list = LinkList.Where(ll => ll.StartId == CurrentNodeModel.NodeId);
                var end_list = LinkList.Where(ll => ll.EndId == CurrentNodeModel.NodeId);

                // 更新连线的起始端坐标
                var node = start_list.FirstOrDefault(sl => sl.StartAnchor == "T");
                if (node != null)
                {
                    node.StartX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
                    node.StartY = CurrentNodeModel.Y + 3;
                }
                node = start_list.FirstOrDefault(sl => sl.StartAnchor == "B");
                if (node != null)
                {
                    node.StartX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
                    node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H - 3;
                }
                node = start_list.FirstOrDefault(sl => sl.StartAnchor == "L");
                if (node != null)
                {
                    node.StartX = CurrentNodeModel.X + 3;
                    node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
                }
                node = start_list.FirstOrDefault(sl => sl.StartAnchor == "R");
                if (node != null)
                {
                    node.StartX = CurrentNodeModel.X + CurrentNodeModel.W - 3;
                    node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
                }

                // 更新连线的终止端坐标
                node = end_list.FirstOrDefault(sl => sl.EndAnchor == "T");
                if (node != null)
                {
                    node.EndX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
                    node.EndY = CurrentNodeModel.Y + 3;
                }
                node = end_list.FirstOrDefault(sl => sl.EndAnchor == "B");
                if (node != null)
                {
                    node.EndX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
                    node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H - 3;
                }
                node = end_list.FirstOrDefault(sl => sl.EndAnchor == "L");
                if (node != null)
                {
                    node.EndX = CurrentNodeModel.X + 3;
                    node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
                }
                node = end_list.FirstOrDefault(sl => sl.EndAnchor == "R");
                if (node != null)
                {
                    node.EndX = CurrentNodeModel.X + CurrentNodeModel.W - 3;
                    node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
                }
                #endregion

                e.Handled = true;
            }
            if (isLinking)
            {
                // 更新当前LinkModel的终点坐标？
                linkModel.EndX = current_point.X;
                linkModel.EndY = current_point.Y;

                e.Handled = true;
            }
        }
        // 鼠标左键在画布上弹起
        private void OnNodeMouseUp()
        {
            _is_moving = false;

            // 清除临时Link
            if (isLinking && linkModel != null)
            {
                LinkList.Remove(linkModel);
                linkModel = null;
                isLinking = false;
            }
        }
        #endregion

        #region 锚点处理
        LinkModel linkModel;
        bool isLinking = false;
        // 当在锚点按下的时候
        private void DoAnchorDown(object obj)
        {
            string[] info = obj.ToString().Split(";");
            string id = info[0];
            // 确定对应的节点（Model）
            NodeModelBase model = NodeList.FirstOrDefault(n => n.NodeId == id);
            if (model == null) return;

            linkModel = new LinkModel
            {
                StartId = id,
                StartAnchor = info[1]
            };

            if (info[1] == "T")
            {
                linkModel.StartX = model.X + (model.W / 2);
                linkModel.StartY = model.Y + 3;
            }
            else if (info[1] == "B")
            {
                linkModel.StartX = model.X + (model.W / 2);
                linkModel.StartY = model.Y + model.H - 3;
            }
            else if (info[1] == "L")
            {
                linkModel.StartX = model.X + 3;
                linkModel.StartY = model.Y + model.H / 2;
            }
            else if (info[1] == "R")
            {
                linkModel.StartX = model.X + model.W - 3;
                linkModel.StartY = model.Y + model.H / 2;
            }

            if (model is DecisionNodeModelBase dnmb)
            {
                // T/F
                linkModel.Condition = info[2];
            }

            linkModel.EndAnchor = "N";
            linkModel.EndX = linkModel.StartX;
            linkModel.EndY = linkModel.StartY;
            //
            LinkList.Add(linkModel);
            isLinking = true;

            isCanvasDrag = false;
        }
        // 当在锚点释放鼠标的时候
        private void DoAnchorUp(object obj)
        {
            string[] info = obj.ToString().Split(";");
            string id = info[0];
            // 确定对应的节点（Model）
            NodeModelBase model = NodeList.FirstOrDefault(n => n.NodeId == id);
            if (model == null || linkModel == null)
            {
                //LinkList.Remove(linkModel);
                return;
            }

            linkModel.EndId = id;
            linkModel.EndAnchor = info[1];

            if (info[1] == "T")
            {
                var result = SetLinkTopPoint(model);
                linkModel.EndX = result.x;
                linkModel.EndY = result.y;
            }
            else if (info[1] == "B")
            {
                linkModel.EndX = model.X + (model.W / 2);
                linkModel.EndY = model.Y + model.H - 3;
            }
            else if (info[1] == "L")
            {
                linkModel.EndX = model.X + 3;
                linkModel.EndY = model.Y + model.H / 2;
            }
            else if (info[1] == "R")
            {
                linkModel.EndX = model.X + model.W - 3;
                linkModel.EndY = model.Y + model.H / 2;
            }
            //LinkList.Add(linkModel);


            // 处理连接成功的节点中当前连线的锚点状态
            // 设置终节点的对应的锚点显示
            model.SetAnchorShow(info[1], false);
            // 设置起始节点的对应铁锚点显示
            var start = NodeList.FirstOrDefault(n => n.NodeId == linkModel.StartId);
            if (start != null)
                start.SetAnchorShow(linkModel.StartAnchor, false);

            model.FlowLevel.Add(start.FlowLevel[0] + 1);

            isLinking = false;

            isCanvasDrag = false;
        }

        private (double x, double y) SetLinkTopPoint(NodeModelBase model)
        {
            double X = model.X + (model.W / 2);
            double Y = model.Y + 3;
            return (X, Y);
        }
        #endregion


        #region 执行节点逻辑
        private void DoRunFlowchart()
        {
            if (cts != null && cts.IsCancellationRequested)
                return;

            this.Log("流程", "[开始]");
            Task.Run(() =>
            {
                //Thread.Sleep(2000);

                DoRunFirst();

                this.Log("流程", "[结束]");

                ReleaseIntPrt();
            });
        }

        private void ReleaseIntPrt()
        {
            var args = this.ArgumentList.Where(a => a.ArgType == "IntPtr").ToList();
            foreach (var item in args)
            {
                object v = item.Value ?? 0;
                if (IntPtr.TryParse(v.ToString(), out IntPtr ptr))
                {
                    DeleteObject(ptr);
                }
            }
        }

        private void DoRunFirst()
        {
            // 开始按顺序执行每个节点中的逻辑
            var node = this.NodeList.FirstOrDefault(n => n.IsStart);
            if (node == null)
            {
                this.Log(node.NodeName, "流程异常，未发现起始节点！");
            }
            else
            {
                if (cts != null && cts.IsCancellationRequested)
                    return;

                DoRun(node);

                if (cts != null && cts.IsCancellationRequested)
                    return;
            }
        }

        private void DoRun(NodeModelBase node)
        {
            if (cts != null && cts.IsCancellationRequested)
                return;

            //Thread.Sleep(2000);

            Stopwatch stopwatch = Stopwatch.StartNew();

            // 这里是每个节点执行的逻辑
            try
            {
                if (cts != null && cts.IsCancellationRequested)
                    return;
                if (node is DecisionNodeModelBase dnmb)
                {
                    // True / False
                    bool result = dnmb.Decision(this);

                    // 找线
                    var lm = this.LinkList.FirstOrDefault(l => l.StartId == node.NodeId && (l.Condition == "T") == result);
                    if (lm == null)
                        return;

                    // 找线另一端的节点
                    var next_node = this.NodeList.FirstOrDefault(n => n.NodeId == lm.EndId);
                    if (next_node != null)
                        this.DoRun(next_node);
                }
                else
                {
                    if (!node.IsStart)
                    {
                        // 执行节点中对应的逻辑
                        node.IsRunning = true;
                        stopwatch.Restart();
                        this.Log(node.NodeName, "[执行]");


                        if (cts != null && cts.IsCancellationRequested)
                            return;
                        node.Execute(this);

                        if (cts != null && cts.IsCancellationRequested)
                            return;


                        //Thread.Sleep(1000);

                        stopwatch.Stop();
                        node.Duration = stopwatch.ElapsedMilliseconds;
                        node.IsRunning = false;
                    }

                    if (cts != null && cts.IsCancellationRequested)
                        return;

                    // 执行完成后，继续下个节点
                    var ls = this.LinkList.Where(l => l.StartId == node.NodeId);
                    foreach (var l in ls)
                    {
                        var next_node = this.NodeList.FirstOrDefault(n => n.NodeId == l.EndId);
                        if (next_node != null)
                            this.DoRun(next_node);
                    }
                }
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                node.Duration = stopwatch.ElapsedMilliseconds;
                node.IsRunning = false;

                this.Log(node.NodeName, ex.Message);
            }
        }

        CancellationTokenSource cts;
        private void DoCircleExecute()
        {
            this.Log("流程", "[开始]");
            cts = new CancellationTokenSource();
            Task.Run(() =>
            {
                do
                {
                    DoRunFirst();
                } while (!cts.IsCancellationRequested);


                this.Log("流程", "[结束]");

                this.ReleaseIntPrt();
            }, cts.Token);
        }

        private void DoStopExecute()
        {
            cts?.Cancel();
        }

        NodeModelBase _currentStepNode;
        bool _decisionResult = false;
        private void DoStepExecute()
        {

            //if (_currentStepNode == null)
            //{
            //    var start = this.NodeList.First();
            //    var link = this.LinkList.FirstOrDefault(l => l.StartId == _currentStepNode.NodeId);
            //    _currentStepNode = this.NodeList.FirstOrDefault(n => n.NodeId == link.EndId);
            //}



            //if (_currentStepNode is DecisionNodeModelBase dnmb)
            //{
            //    _decisionResult = dnmb.Decision(this);
            //}
            //else
            //{
            //    _currentStepNode.Execute(this);
            //    var ls = this.LinkList.Where(l => l.StartId == _currentStepNode.NodeId).ToList();
            //    _currentStepNode = this.NodeList.FirstOrDefault(n => n.NodeId == ls[0].EndId);
            //}

            var ns = this.NodeList.Where(n => n.FlowLevel.Contains(_currentLevel)).ToList();

            var ids = this.LinkList.ToList()
                .Where(l => l.EndId == ns[_subIndex].NodeId &&
                     (l.Condition == "T") == _decisionResult).ToList()
                     .Select(ll => ll.EndId).ToList();
            ns = ns.Where(n => ids.Contains(n.NodeId)).ToList();

            //if (this.LinkList.ToList().Exists(l => l.EndId == ns[_subIndex].NodeId &&
            //         (l.Condition == "T") == _decisionResult))
            {
                if (ns[_subIndex] is DecisionNodeModelBase dnmb)
                {
                    _decisionResult = dnmb.Decision(this);
                }
                else
                {
                    ns[_subIndex].Execute(this);
                }
            }

            _subIndex++;
            if (_subIndex >= ns.Count)
            {
                _currentLevel = ns[_subIndex - 1].FlowLevel[0] + 1;
                if (_currentLevel > this.NodeList.Max(n => n.FlowLevel.Max(fl => fl)))
                    _currentLevel = 1;
                _subIndex = 0;
            }
        }
        int _currentLevel = 1;
        int _subIndex = 0;
        #endregion

        #region 添加参数
        private void DoAddArgument()
        {
            ArgumentList.Add(new FlowArgModel());
        }
        private void DoDelArgument(object obj)
        {
            ArgumentList.Remove(obj as FlowArgModel);
        }

        private void DoSelectFolder(object obj)
        {
            var model = obj as NodeArgModel;

            OpenFolderDialog dialog = new OpenFolderDialog();
            if (dialog.ShowDialog() == true)
                model.ArgValue = dialog.FolderName;
        }
        #endregion


        // 这里内存一直增长   需要优化
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool DeleteObject(IntPtr hObject);

        public void ShowImage(IntPtr img_handler)
        {
            BitmapImage bitmapImage = new BitmapImage();
            using (var ms = new MemoryStream())
            {
                System.Drawing.Bitmap bitmap =
                    System.Drawing.Bitmap.FromHbitmap(img_handler);

                bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                ms.Position = 0;

                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.StreamSource = ms;
                bitmapImage.EndInit();
                bitmapImage.Freeze();
            }

            PreviewImage = bitmapImage;
            //DeleteObject(img_handler);
        }


        public string FilePath { get; set; }

        public void Save()
        {
            // 选择保存地址---再保存的进候需要选择？
            if (string.IsNullOrEmpty(FilePath))
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = "流程文件(*.flw)|*.flw";
                if (dialog.ShowDialog() == true)
                {
                    FilePath = dialog.FileName;
                }
            }

            try
            {
                // Bug：简单的Json文件保存会导致实例丢失   无法执行实例中的方法
                // 需要处理！！！！！

                // 每个子项单独保存  记录类型名称
                // 通信序列化对象进行多态对象的序列化与反序列，需要对基类进行配置
                string node_json = System.Text.Json.JsonSerializer.Serialize(this.NodeList);
                string link_json = System.Text.Json.JsonSerializer.Serialize(this.LinkList);
                string arg_json = System.Text.Json.JsonSerializer.Serialize(this.ArgumentList);

                string temp =
                    this.Title + "@#$#@" +
                    node_json + "@#$#@" +
                    link_json + "@#$#@" +
                    arg_json;

                System.IO.File.WriteAllText(FilePath, temp);
            }
            catch (Exception ex)
            {
                this.Log("流程保存", ex.Message);
            }
        }


        #region 画布缩放
        public void DoMainZoom(object sender, MouseWheelEventArgs e)
        {
            //e.GetPosition
            this.MainZoom += e.Delta > 0 ? 0.05 : -0.05;

            // 检查放缩放比，  在1.5和0.5之间缩放   倍数
            if (MainZoom < 0.5)
                MainZoom = 0.5;
            if (MainZoom > 1.5)
                MainZoom = 1.5;


            var hwakeye = (sender as FrameworkElement).Tag;
            this.CheckCanvasLocation(sender, hwakeye);
        }



        public void DoCanvasMouseMove(object? sender, MouseEventArgs e)
        {
            if (isCanvasDrag && !isLinking && !_is_moving)
            {
                Point p = e.GetPosition((IInputElement)e.Source);
                // 
                double x = p.X - startCanvas.X;
                double y = p.Y - startCanvas.Y;

                DragX += x;
                DragY += y;

                var hwakeye = (sender as FrameworkElement).Tag;
                CheckCanvasLocation(sender, hwakeye);
            }
        }

        private void CheckCanvasLocation(object? sender, object hwakeye)
        {
            var canvas = sender as FrameworkElement;

            var parent = canvas.Parent as FrameworkElement;
            // -250 -200
            Point left_top = canvas.TranslatePoint(new Point(0, 0), parent);
            Point right_bottom = canvas.TranslatePoint(new Point(canvas.ActualWidth, canvas.ActualHeight), parent);
            double trans_w = right_bottom.X - left_top.X;
            double trans_h = right_bottom.Y - left_top.Y;

            if (left_top.X > 0)
            {
                DragX = (trans_w - parent.ActualWidth) / 2;
            }
            if (left_top.Y > 0)
            {
                DragY = (trans_h - parent.ActualHeight) / 2;
            }
            if (right_bottom.X < parent.ActualWidth)
            {
                DragX = (trans_w - parent.ActualWidth) / 2 * -1;
            }
            if (right_bottom.Y < parent.ActualHeight)
            {
                DragY = (trans_h - parent.ActualHeight) / 2 * -1;
            }


            // 鹰眼缩放
            this.HwakeyeZoom = parent.ActualWidth / trans_w / 0.5;

            // 鹰眼位移
            var fe = hwakeye as FrameworkElement;
            this.HwakeyeDragX = (DragX * -1 / canvas.ActualWidth) * fe.ActualWidth;
            this.HwakeyeDragY = (DragY * -1 / canvas.ActualHeight) * fe.ActualHeight;
        }

        private void DoCanvasMouseUp(object? obj)
        {
            isCanvasDrag = false;
        }

        bool isCanvasDrag = false;
        Point startCanvas = new Point(0, 0);
        private void DoCanvasMouseDown(object? obj)
        {
            var e = obj as MouseButtonEventArgs;
            isCanvasDrag = true;
            startCanvas = e.GetPosition((IInputElement)e.Source);
        }




        bool is_hwakeye_drag = false;
        Point hwakeye_down_p = new Point(0, 0);
        FrameworkElement fe_hwakeye_view = null;
        public void HwakeyeViewMouseDown(object sender, MouseButtonEventArgs e)
        {
            is_hwakeye_drag = true;
            hwakeye_down_p = e.GetPosition((IInputElement)sender);
            fe_hwakeye_view = sender as FrameworkElement;
        }
        public void HwakeyeMouseMove(object sender, MouseEventArgs e)
        {
            if (is_hwakeye_drag)
            {
                Point p = e.GetPosition((IInputElement)e.Source);

                double x = p.X - hwakeye_down_p.X;
                double y = p.Y - hwakeye_down_p.Y;

                HwakeyeDragX += x;
                HwakeyeDragY += y;

                // 边缘检测
                var parent = sender as FrameworkElement;
                Point left_top = fe_hwakeye_view.TranslatePoint(new Point(0, 0), parent);
                Point right_bottom = fe_hwakeye_view.TranslatePoint(new Point(fe_hwakeye_view.ActualWidth, fe_hwakeye_view.ActualHeight), parent);
                double trans_w = right_bottom.X - left_top.X;
                double trans_h = right_bottom.Y - left_top.Y;

                if (left_top.X < 0)
                {
                    HwakeyeDragX = (trans_w - parent.ActualWidth) / 2;
                }
                if (left_top.Y < 0)
                {
                    HwakeyeDragY = (trans_h - parent.ActualHeight) / 2;
                }
                if (right_bottom.X > parent.ActualWidth)
                {
                    HwakeyeDragX = (trans_w - parent.ActualWidth) / 2 * -1;
                }
                if (right_bottom.Y > parent.ActualHeight)
                {
                    HwakeyeDragY = (trans_h - parent.ActualHeight) / 2 * -1;
                }


                // 同步画布的位移
                var canvas = (sender as FrameworkElement).Tag as FrameworkElement;
                DragX = HwakeyeDragX * -1 / parent.ActualWidth * canvas.ActualWidth;
                DragY = HwakeyeDragY * -1 / parent.ActualHeight * canvas.ActualHeight;
            }
        }
        public void HwakeyeMouseUp(object sender, MouseButtonEventArgs e)
        {
            is_hwakeye_drag = false;
        }




        private void DoZoomIncrease(object? obj)
        {
            this.MainZoom += 0.05;

            // 检查放缩放比，  在1.5和0.5之间缩放   倍数
            if (MainZoom > 1.5)
                MainZoom = 1.5;

            var hwakeye = (obj as FrameworkElement).Tag;
            this.CheckCanvasLocation(obj, hwakeye);
        }

        private void DoZoomReduce(object? obj)
        {
            this.MainZoom -= 0.05;

            // 检查放缩放比，  在1.5和0.5之间缩放   倍数
            if (MainZoom < 0.5)
                MainZoom = 0.5;

            var hwakeye = (obj as FrameworkElement).Tag;
            this.CheckCanvasLocation(obj, hwakeye);
        }

        private void DoZoomReset(object? obj)
        {
            this.MainZoom = 1;

            var hwakeye = (obj as FrameworkElement).Tag;
            this.CheckCanvasLocation(obj, hwakeye);
        }
        #endregion



        private void Log(string node_name, string message)
        {
            Application.Current.Dispatcher.Invoke(new Action(() =>
            {
                if (LogList.Count>1000)
                {
                    LogList.RemoveAt(0);
                }
                // 数据量增大  
                this.LogList.Add(new LogModel
                {
                    Time = DateTime.Now,
                    NodeName = node_name,
                    LogMessage = message,
                });
            }));
        }
    }
}
